یکی از ویژگی های کلیدی استاندارد اجزای وب ، توانایی ایجاد عناصر سفارشی است که عملکرد شما را در یک صفحه HTML محصور می کند ، نه اینکه مجبور شوید با یک عنصر طولانی و تو در تو که در کنار هم یک ویژگی صفحه سفارشی دارند ، کار کنید. در این مقاله استفاده از Custom Elements API معرفی شده است.
توجه: عناصر سفارشی به طور پیش فرض در Firefox ، Chrome و Edge پشتیبانی می شوند (76). اپرا و سافاری تاکنون فقط از عناصر سفارشی مستقل پشتیبانی می کنند.
نمای سطح بالا
کنترل کننده عناصر سفارشی در یک سند وب ، شی CustomElementRegistry
است - این شی به شما امکان می دهد یک عنصر سفارشی را در صفحه ثبت کنید ، اطلاعات مربوط به عناصر سفارشی را ثبت کنید و غیره.
برای ثبت یک عنصر سفارشی در صفحه ، از روش ()CustomElementRegistry.define
استفاده می کنید. آرگومان های خود را در نظر می گیرد:
DOMString
نمایانگر نامی که به عنصر می دهید. توجه داشته باشید که نام عناصر سفارشی برای استفاده از آنها به یک خط تیره احتیاج دارد (kebab-case). آنها نمی توانند تک کلمه ای باشند.extends
است ، عنصر داخلی ساخته شده از عنصر شما را مشخص می کند ، در صورت وجود (فقط مربوط به عناصر داخلی سفارشی است).بنابراین به عنوان مثال ، ما می توانیم یک عنصر word-count سفارشی مانند این تعریف کنیم:
customElements.define('word-count', WordCount, { extends: 'p' });
عنصر word-count
نامیده می شود ، شی کلاس آن WordCount
است و عنصر <p>
را گسترش می دهد.
شی کلاس یک عنصر سفارشی با استفاده از نحو کلاس استاندارد ES 2015 نوشته می شود. به عنوان مثال ، WordCount
مانند این ساختار است:
class
WordCount
extends
HTMLParagraphElement
{
constructor()
{
// Always call super first in constructor
super();
// Element functionality written in here
...
}
}
این فقط یک مثال ساده است ، اما کارهای بیشتری در اینجا می توانید انجام دهید. در داخل کلاس می توان پاسخ های خاص چرخه حیات را تعریف کرد ، که در نقاط خاصی از چرخه حیات عنصر اجرا می شوند. به عنوان مثال ، هر بار که عنصر سفارشی به یک عنصر متصل به سند متصل می شود ، connectedCallback
فراخوانی می شود ، در حالی که هنگامی که یکی از ویژگی های عنصر سفارشی اضافه ، حذف یا تغییر می یابد ، attributeChangedCallback
فراخوانی می شود.
درباره این موارد در بخش استفاده از بازگشت تماس با چرخه عمر در زیر اطلاعات کسب خواهید کرد.
دو نوع عنصر سفارشی وجود دارد:
<popup-info>
، یا document.createElement("popup-info") .is
استفاده می شوند. به عنوان مثال <p is="word-count">
, or document.createElement("p", { is: "word-count" })
.
چند مثال ساده
در این مرحله ، بیایید چند نمونه ساده دیگر را مرور کنیم تا نحوه ایجاد عناصر سفارشی را با جزئیات بیشتری به شما نشان دهیم.
عناصر سفارشی مستقل
بیایید نگاهی به مثالی از یک عنصر سفارشی مستقل بیندازیم - <popup-info-box> . این یک نماد تصویر و یک رشته متن را می گیرد و نماد را در صفحه جاسازی می کند. وقتی نماد متمرکز است ، متن را در یک جعبه اطلاعات پاپ آپ نمایش می دهد تا اطلاعات بیشتری در متن ارائه دهد.
برای شروع ، فایل جاوا اسکریپت یک کلاس به نام PopUpInfo
تعریف می کند ، که کلاس عمومی HTMLElement
را گسترش می دهد(از آن ارث بری می کند).
class
PopUpInfo
extends
HTMLElement
{
constructor()
{
// Always call super first in constructor
super();
// write element functionality in here
...
}
}
قطعه کد قبلی شامل تعریف ()constructor برای کلاس است که همیشه با فراخوانی ()super شروع می شود تا زنجیره نمونه اولیه صحیح برقرار شود.
در داخل سازنده ، ما تمام کارایی عنصر را هنگام نمونه سازی از آن تعریف می کنیم. در این حالت ما یک ریشه سایه به عنصر سفارشی وصل می کنیم ، با استفاده از برخی دستکاری های DOM ساختار داخلی DOM سایه را ایجاد می کنیم - که سپس به ریشه سایه متصل می شود - و در آخر مقداری CSS را به ریشه سایه وصل می کنیم تا اساتیل دهی شود.
// Create a shadow root
this.attachShadow({mode
:
'open'});
// sets and returns 'this.shadowRoot'
// Create (nested) span elements
const wrapper
= document
.createElement('span');
wrapper
.setAttribute('class','wrapper');
const icon
= wrapper
.appendChild(document
.createElement('span'));
icon
.setAttribute('class','icon');
icon
.setAttribute('tabindex',
0);
// Insert icon from defined attribute or default icon
const img
= icon
.appendChild(document
.createElement('img'));
img
.src
=
this.hasAttribute('img')
?
this.getAttribute('img')
:
'img/default.png';
const info
= wrapper
.appendChild(document
.createElement('span'));
info
.setAttribute('class','info');
// Take attribute content and put it inside the info span
info
.textContent
=
this.getAttribute('data-text');
// Create some CSS to apply to the shadow dom
const style
= document
.createElement('style');
style
.textContent
=
'.wrapper {'
+
// CSS truncated for brevity
// attach the created elements to the shadow DOM
this.shadowRoot
.append(style
,wrapper
);
سرانجام ، ما با استفاده از متد ()define که قبلاً ذکر کردیم ، عنصر سفارشی خود را در CustomElementRegistry ثبت می کنیم - در پارامترها نام عنصر را تعیین می کنیم ، و سپس نام کلاس را تعریف می کنیم:
customElements
.define('popup-info', PopUpInfo
);
اکنون برای استفاده در صفحه آماده است. در HTML ، از آن بصورت زیر استفاده می کنیم:
<popup-info img="img/alt.png" data-text="Your card validation code (CVC)
is an extra security feature — it is the last 3 or 4 numbers on the
back of your card."></popup-info>
توجه: کد منبع کامل جاوا اسکریپت را می توانید در اینجا مشاهده کنید.
استایل های داخلی در مقابل خارجی
در مثال فوق ما با استفاده از عنصر <style>
سبک را به Shadow DOM اعمال می کنیم ، اما انجام این کار با ارجاع یک صفحه استایل از یک عنصر <link>
کاملاً امکان پذیر است.
به عنوان مثال ، از مثال popup-info-box-external-stylesheet ما به این کد نگاهی بیندازید (کد منبع را ببینید):
// Apply external styles to the shadow dom
const linkElem
= document
.createElement('link');
linkElem
.setAttribute('rel',
'stylesheet');
linkElem
.setAttribute('href',
'style.css');
// Attach the created element to the shadow dom
shadow
.appendChild(linkElem
);
توجه داشته باشید که عناصر <link>
رنگ ریشه سایه را مسدود نمی کنند ، بنابراین ممکن است در هنگام بارگیری صفحه استایل ، فلش محتوای بدون مدل (FOUC) وجود داشته باشد.
بسیاری از مرورگرهای مدرن بهینه سازی را برای برچسب های <style>
یا از یک گره مشترک شبیه سازی شده یا دارای متن یکسان انجام می دهند ، به آنها امکان می دهد یک صفحه استایل پشتیبان را به اشتراک بگذارند. با استفاده از این بهینه سازی ، عملکرد اسایل های خارجی و داخلی باید یکسان باشد.
عناصر داخلی سفارشی
حال بیایید نگاهی به مثال سفارشی ساخته شده در عنصر دیگر - expanding-list (آن را نیز مشاهده کنید). با این کار هر لیست مرتب نشده به یک منوی در حال گسترش / در حال فروپاشی تبدیل می شود.
اول از همه ، کلاس عنصر خود را به همان روش قبلی تعریف می کنیم:
class
ExpandingList
extends
HTMLUListElement
{
constructor()
{
// Always call super first in constructor
super();
// write element functionality in here
...
}
}
ما در اینجا عملکرد عنصر را به هیچ وجه توضیح نمی دهیم ، اما شما می توانید با بررسی کد منبع نحوه کارکرد آن را دریابید. تنها تفاوت واقعی در اینجا این است که عنصر ما حاصل از گسترش رابط HTMLUListElement
است و نه HTMLElement
. بنابراین این ویژگی به جای اینکه یک عنصر مستقل باشد ، دارای تمام ویژگی های یک عنصر <ul>
با عملکردی است که در بالا تعریف شده است. این همان چیزی است که آن را به جای یک عنصر مستقل ، به یک ساخته شده داخلی سفارشی تبدیل می کند.
در مرحله بعد ، ما عنصر را مانند قبل با استفاده از روش define() ثبت می کنیم ، با این تفاوت که این بار همچنین شامل یک شی انتخابی است که نشان می دهد عنصر ساخته شده از کدام عنصر ارث بری می کند:
customElements
.define('expanding-list', ExpandingList
,
{
extends:
"ul"
});
استفاده از عنصر داخلی در یک سند وب نیز تا حدودی متفاوت به نظر می رسد:
<ul is="expanding-list">
...
</ul>
شما از عنصر <ul> به صورت عادی استفاده می کنید اما نام عنصر سفارشی را در مشخصه is مشخص کنید.
توجه: مجدداً می توانید کد منبع کامل جاوا اسکریپت را در اینجا مشاهده کنید.
استفاده از برگشتهای چرخه عمر
شما می توانید چندین پاسخ مختلف در داخل تعریف کلاس عنصر سفارشی تعریف کنید ، که در نقاط مختلف چرخه حیات عنصر ایجاد می شود:
توجه: ممکن است هنگامی که المنت شما دیگر متصل نیست ، connectedCallback فراخوانی شود ، برای اطمینان از Node.isConnected
استفاده کنید.
بیایید به نمونه ای از این موارد در حال استفاده نگاه کنیم. کد زیر از مثال مربوط به بازگشت چرخه حیات گرفته شده است (مشاهده کنید که به صورت زنده اجرا می شود). این یک مثال بی اهمیت است که یک مربع رنگی با اندازه ثابت در صفحه ایجاد می کند. عنصر سفارشی به این شکل است:
<custom-square l="100" c="red"></custom-square>
سازنده کلاس واقعاً ساده است - در اینجا ما یک DOM سایه را به عنصر وصل می کنیم ، سپس عناصر خالی <div> و <style> را به ریشه سایه وصل می کنیم:
const shadow
=
this.attachShadow({mode
:
'open'});
const div
= document
.createElement('div');
const style
= document
.createElement('style');
shadow
.appendChild(style
);
shadow
.appendChild(div
);
عملکرد اصلی در این مثال updateStyle() است - یک عنصر را می گیرد ، ریشه سایه خود را پیدا می کند ، عنصر <style> خود را پیدا می کند ، و عرض ، ارتفاع و رنگ پس زمینه را به استایل اضافه می کند.
function
updateStyle(elem)
{
const shadow
= elem
.shadowRoot
;
shadow
.querySelector('style').textContent
=
`
div {
width: ${elem.getAttribute('l')}px;
height: ${elem.getAttribute('l')}px;
background-color: ${elem.getAttribute('c')};
}
`;
}
به روزرسانی های واقعی توسط بازگرداندن چرخه زندگی انجام می شوند ، که به عنوان متد در داخل تعریف کلاس قرار می گیرند. ()connectedCallback هر بار که عنصر به DOM اضافه می شود اجرا می شود - در اینجا ما تابع ()updateStyle را اجرا می کنیم تا مطمئن شویم که مربع به شکلی که در ویژگی های آن تعریف شده است ، شکل می گیرد:
connectedCallback()
{
console
.log('Custom square element added to page.');
updateStyle(this);
}
فراخوان های disconnectedCallback()
و adoptedCallback()
پیام های ساده ای را به کنسول وارد می کنند تا وقتی عنصر یا از DOM برداشته می شود یا به صفحه دیگری منتقل می شود ، به ما اطلاع می دهد:
disconnectedCallback()
{
console
.log('Custom square element removed from page.');
}
adoptedCallback()
{
console
.log('Custom square element moved to new page.');
}
()attributeChangedCallback هر زمان که یکی از ویژگی های عنصر به طریقی تغییر کند ، اجرا می شود. همانطور که از خصوصیات آن مشاهده می کنید ، می توان براساس ویژگی ها به صورت جداگانه عمل کرد ، به نام آنها و مقادیر ویژگی های قدیمی و جدید نگاه کرد. در این حالت ، ما فقط تابع ()updateStyle را دوباره اجرا می کنیم تا مطمئن شویم که استایل مربع مطابق با مقادیر جدید به روز شده است:
attributeChangedCallback(name, oldValue, newValue)
{
console
.log('Custom square element attributes changed.');
updateStyle(this);
}
توجه داشته باشید که برای دریافت پاسخ به ویژگی ()attributeChangedCallback در هنگام تغییر ویژگی ، باید ویژگی ها را مشاهده کنید. این کار با مشخص کردن متد ()static get observedAttributes در کلاس عنصر سفارشی انجام می شود - باید یک آرایه را برگرداند که حاوی نام ویژگی هایی است که می خواهید مشاهده کنید:
static
get
observedAttributes()
{
return
['c',
'l'];
}
در مثال ما ، درست در بالای سازنده قرار دارد.
توجه: منبع کامل جاوا اسکریپت را در اینجا پیدا کنید.
مبدل ها در مقابل کلاس ها
لطفا توجه داشته باشید که کلاسهای ES2015 نمی توانند به طور قابل اعتماد در Babel 6 یا TypeScript مرورگرهای قدیمی را هدف قرار دهند. شما می توانید از Babel 7 یا کلاسهای babel-plugin-transform-builtin برای Babel 6 استفاده کنید و ES2015 را در TypeScript به جای میراث هدف قرار دهید.
کتابخانه ها
چندین کتابخانه وجود دارد که با هدف افزایش سطح انتزاع هنگام ایجاد عناصر سفارشی ، روی اجزای وب ساخته شده اند. برخی از این کتابخانه ها در ادامه آمده است:
برای ثبت نظر باید وارد سایت شوید یا ثبت نام نمایید.
نظر شما با موفقیت در سیستم ثبت گردید.